 #coding:utf-8
require 'win32ole'
load 'pic_to_str.rb'

HTTPS_HOST='https://dynamic.12306.cn'

client = HTTPClient.new(:agent_name =>'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)')
#证书路径
client.ssl_config.add_trust_ca "srcr.cer"

#验证码图片地址
image_code = 'https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=lrand&' + rand().to_s

#登录网址
url='https://dynamic.12306.cn/otsweb/loginAction.do?method=init'

query_url = 'https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=queryststrainall'

#登录表单的action
action = nil
cookie = nil

pic_sites = [PictureToStr_tesseract.new, PictureToStr_gocr.new]#, PictureToStr_freeocr.new, PictureToStr_ocr_extract.new]

puts "#{Time.now.to_s} starting .."
begin

	Timeout::timeout(5) {
	page = client.get url
	
	File.open('login.html', 'w'){|f| page.dump(f)}
	
	doc = Nokogiri::HTML(page.content)
	forms = doc.css("div.conWrap form")
	action = forms[0]['action']
	}
rescue => err
	puts err.to_s
	retry 
end

#失败则重刷验证码
begin
	res = nil
	Timeout::timeout(5){ res = client.get(image_code) }
	#保存验证码的图片为1.jpg
	File.open('1.jpg', 'w') {|f| f.syswrite res.content}
	pic_code = nil
	pic_sites.each do |e|
		begin
			Timeout::timeout(20) {
			#puts "begin #{e.to_s}"
				pic_code = e.get_str
			}	
			break if !pic_code.nil? 	
		rescue =>err
			puts "#{e.to_s} - #{err.to_s}"
		end
	end
	
	raise "pic_code is nil" if pic_code.nil?
	
	puts "pic code is #{pic_code}"
	
	form = {
		'loginUser.user_name'=>'suzhijie325', 
		'nameErrorFocus'=>'', 
		'user.password'=>'9852098520', 
		'passwordErrorFocus'=>'',
		'randCode'=>pic_code,
		'randErrorFocus'=>'focus'
	}

	#发送登录消息
	print "try login...\n"
	begin 
		Timeout::timeout(5) { res = client.post(HTTPS_HOST + action, form) }
	rescue => err 
		puts "rety login ..."
		retry 
	end
	
	doc = Nokogiri::HTML(res.content)
	File.open('login_s.html', 'w'){|f| res.dump(f)}
	raise "pic code error!" if res.content =~ /请输入正确的验证码/
	raise "too many peploe" if res.content =~ /访问用户过多/
	raise "erorr:plz check login.htm" if res.content !~ /系统消息/
	
	puts "#{Time.now.to_s} login success.."
	
	res = client.get HTTPS_HOST + '/otsweb/order/querySingleAction.do?method=init'
	File.open('book.html', 'w'){|f| res.dump(f)}
	
	#ie = WIN32OLE.new("InternetExplorer.Application")
	#ie.visible=true
	#ie.Navigate "#{HTTPS_HOST}/otsweb/order/querySingleAction.do?method=init"
	#exit
	#File.open('success.html', 'w'){|f| f.syswrite res.content}
	#查询票数的信息
	#查询票数的信息
	#https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=queryLeftTicket&orderRequest.train_date=2011-12-25&orderRequest.from_station_telecode=BXP&orderRequest.to_station_telecode=FZS&orderRequest.train_no=2400000Z5905&trainPassType=QB&trainClass=QB%23D%23Z%23T%23K%23QT%23&includeStudent=00&seatTypeAndNum=&orderRequest.start_time_str=00%3A00--24%3A00
	#[{"end_station_name":"福州","end_time":"22:43","id":"240000D36500","start_station_name":"北京南","start_time":"07:50","value":"D365"},{"end_station_name":"福州","end_time":"05:49","id":"120000K66808","start_station_name":"沈阳北","start_time":"17:07","value":"K668/K665"}]
	#确定预定地址
	#https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=init
	#station_train_code=2400000Z5905&train_date=2011-12-25&seattype_num=&from_station_telecode=BXP&to_station_telecode=FZS&
	#include_student=00&from_station_telecode_name=%E5%8C%97%E4%BA%AC&to_station_telecode_name=%E7%A6%8F%E5%B7%9E&round_train_date=&round_start_time_str=00%3A00--24%3A00&
	#single_round_type=1&train_pass_type=QB&train_class_arr=QB%23D%23Z%23T%23K%23QT%23&start_time_str=00%3A00--24%3A00&lishi=1183&train_start_time=15%3A08
	form = 
	{
	'station_train_code'=>'2400000Z5905', 'train_date'=>'2012-01-18','seattype_num'=>'', 'from_station_telecode'=>'BXP','to_station_telecode'=>'FZS',
	'include_student'=>'00','from_station_telecode_name'=>'北京', 'to_station_telecode_name'=>'福州','round_train_date'=>'','round_start_time_str'=>'00:00--24:00',
	'single_round_type'=>1,'train_pass_type'=>'QB', 'train_class_arr'=>'QB#D#Z#T#K#QT#','start_time_str'=>'00:00--24:00', 'lishi'=>1183, 'train_start_time'=>'15:08'
	}
	
	confirm_book_page = nil
	begin 
		#必须发2次，第一次返回302错误，并给回一个网址重定向。
		res = client.get 'https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=submutOrderRequest', form
			File.open('redict.html', 'w'){|f| res.dump(f)}
		res = client.get 'https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=init', form
			File.open('confire.html', 'w'){|f| res.dump(f)}
		if res.content !~ /车票预订/ then
			raise 'system busy' if res.content =~ /系统忙/
			File.open('query.html', 'w'){|f| f.syswrite res.content}
			raise 'unkonw error: plz check query.html'
		end
		
		confirm_book_page = res.content
		
	rescue => err	
		puts "#{Time.now} error:#{err.to_s}"
		sleep (rand() * 100 % 5) + 1
		retry
	end
	
	#再次获取验证码
	begin 
		puts "get book pic code.."
		#新的图片验证码地址/otsweb/passCodeAction.do?rand=randp
		res = client.get "https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=randp&#{rand().to_s}"
		#保存验证码的图片为1.jpg
		File.open('1.jpg', 'w') {|f| f.syswrite res.content}
		pic_code = nil
		
		pic_sites.each do |e|
			begin
				Timeout::timeout(20) {
				puts "#{Time.now.to_s} begin #{e.to_s}"
				pic_code = e.get_str
				}
				break
			rescue =>err
				puts "#{Time.now.to_s} get pic fail: #{e.to_s} - #{err.to_s}"
			end
		end
		
		raise 'pic code is nil' if pic_code.nil?
		
		puts "#{Time.now.to_s} the pic code is #{pic_code}"
		
		tokens = Nokogiri::HTML(confirm_book_page).css('input[name$=TOKEN]')
		
		raise 'get org.apache.struts.taglib.html.TOKEN fail' if tokens.length != 1 
		
	#最终提交订单信息
	#https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=confirmPassengerInfoSingle
	#org.apache.struts.taglib.html.TOKEN=74a9e5c65faae70950a2222addec9a59&textfield=&checkbox0=0&orderRequest.train_date=2011-12-25&orderRequest.train_no=2400000Z5905&orderRequest.station_train_code=Z59&orderRequest.from_station_telecode=BXP&orderRequest.to_station_telecode=FZS&orderRequest.seat_type_code=&orderRequest.ticket_type_order_num=&orderRequest.bed_level_order_num=000000000000000000000000000000&orderRequest.start_time=15%3A08&orderRequest.end_time=10%3A51&orderRequest.from_station_name=%E5%8C%97%E4%BA%AC%E8%A5%BF&orderRequest.to_station_name=%E7%A6%8F%E5%B7%9E&orderRequest.cancel_flag=1&orderRequest.id_mode=Y&passengerTickets=1%2C1%2C%E8%8B%8F%E5%BF%97%E6%9D%B0%2C1%2C350524198508081513%2C13821339584%2CY&oldPassengers=%E8%8B%8F%E5%BF%97%E6%9D%B0%2C1%2C350524198508081513&passenger_1_seat=1&passenger_1_ticket=1&passenger_1_name=%E8%8B%8F%E5%BF%97%E6%9D%B0&passenger_1_cardtype=1&passenger_1_cardno=350524198508081513&passenger_1_mobileno=13821339584&checkbox9=Y&oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&randCode=5r71&orderRequest.reserve_flag=A
	#org.apache.struts.taglib.html.TOKEN=8f60a9752e59238f4c83a37f22647efb&textfield=&checkbox0=0&orderRequest.train_date=2011-12-25&
	#orderRequest.train_no=240000D36500&orderRequest.station_train_code=D365&orderRequest.from_station_telecode=VNP&
	#orderRequest.to_station_telecode=FZS&orderRequest.seat_type_code=&orderRequest.ticket_type_order_num=&
	#orderRequest.bed_level_order_num=000000000000000000000000000000&orderRequest.start_time=07%3A50&orderRequest.end_time=22%3A43&
	#orderRequest.from_station_name=%E5%8C%97%E4%BA%AC%E5%8D%97&orderRequest.to_station_name=%E7%A6%8F%E5%B7%9E&orderRequest.cancel_flag=1&
	#orderRequest.id_mode=Y&passengerTickets=O%2C1%2C%E8%8B%8F%E5%BF%97%E6%9D%B0%2C1%2C350524198508081513%2C13821339584%2CY&
	#oldPassengers=%E8%8B%8F%E5%BF%97%E6%9D%B0%2C1%2C350524198508081513&passenger_1_seat=O&passenger_1_ticket=1&passenger_1_name=%E8%8B%8F%E5%BF%97%E6%9D%B0&
	#passenger_1_cardtype=1&passenger_1_cardno=350524198508081513&passenger_1_mobileno=13821339584&checkbox9=Y&
	#oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&oldPassengers=&checkbox9=Y&
	#randCode=zqjp&orderRequest.reserve_flag=A	


	res = client.post 'https://dynamic.12306.cn/otsweb/order/confirmPassengerAction.do?method=confirmPassengerInfoSingle', form
	confirm_book_page = res.content
	File.open('result.html', 'w'){|f| res.dump f}
	
	if res.content !~ /目前您还有未处理的订单/ then 
	
		if res.content =~ /.+?message = \"(.+)\"/ then 
			raise $1
		end
		
		if res.content =~ /title\>(.*)\</ then 
			raise $1
		end
		
		puts "unknow error, check  result.html"
		exit
	end

	puts "#{Time.now.to_s} prebook success..."

	rescue => err
		puts "#{Time.now.to_s} book fail:#{err.to_s}"
		sleep 2
		retry
	end
	

rescue =>err
	puts "#{err.to_s} \n\n"
	#sleep 1
	puts "#{Time.now.to_s} retry get new code picture"
	retry
end

